#ifndef __INTERFACE_PORT_H__
#define __INTERFACE_PORT_H__

#include <stdlib.h>

#define RUN_ON_LINUX (1)


#if RUN_ON_LINUX
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

/*
SPI_TP_BEGIN、SPI_TP_COMMIT是添加在driver/spidev.c的附加属性
必须锁SPI控制器，仅锁设备协议没有用
*/
// #define SPI_ONLY_ONE_BEGIN           _IOR(SPI_IOC_MAGIC, 7, __u8)
// #define SPI_ONLY_ONE_COMMIT          _IOR(SPI_IOC_MAGIC, 7, __u8)

#define SPI_TP_BEGIN        _IOR(SPI_IOC_MAGIC, 5, __u8)
#define SPI_TP_COMMIT       _IOR(SPI_IOC_MAGIC, 6, __u8)

#define SPI_ONLY_ONE_BEGIN  _IOR(SPI_IOC_MAGIC, 7, __u8)
#define SPI_ONLY_ONE_COMMIT _IOR(SPI_IOC_MAGIC, 8, __u8)


#if defined(CONFIG_ONLY_ONE_MUTEX_ON_SPIDEV)
// 锁定所有spidevX.Y设备 3.1.rc1 新增
#define mutex_init(x, y) pthread_mutex_init((x), (y))
#define mutex_destroy(x) pthread_mutex_destroy((x))
#define mutex_lock(x)                      \
    ioctl(dev->fd, SPI_ONLY_ONE_BEGIN, 0); \
    pthread_mutex_lock((x));
#define mutex_unlock(x)        \
    pthread_mutex_unlock((x)); \
    ioctl(dev->fd, SPI_ONLY_ONE_COMMIT, 0);
#else
// 只锁定spidevX.X同名设备
#define mutex_init(x, y) pthread_mutex_init((x), (y))
#define mutex_destroy(x) pthread_mutex_destroy((x))
#define mutex_lock(x)                \
    ioctl(dev->fd, SPI_TP_BEGIN, 0); \
    pthread_mutex_lock((x));
#define mutex_unlock(x)        \
    pthread_mutex_unlock((x)); \
    ioctl(dev->fd, SPI_TP_COMMIT, 0);
// #define mutex_init(x, y)
// #define mutex_destroy(x)
// #define mutex_lock(x) ioctl(dev->fd, SPI_TP_BEGIN, 0);
// #define mutex_unlock(x) ioctl(dev->fd, SPI_TP_COMMIT, 0);
#endif


// 操作系统相关API
static void inline *os_free(void *ptr)
{
    free(ptr);
}

static void inline *os_malloc(size_t size)
{
    return malloc(size);
}

// 注意：这个是操作SPI控制器设备，等同于linux的open，不是标准c库的文件操作fopen
static int inline os_open(const char *pathname, int flags)
{
    return open(pathname, flags);
}

static int inline os_close(int fd)
{
    return close(fd);
}


struct fpga_dev;

/**
 * @brief	fpga 通过SPI方式传输
 * @param[in]	dev 设备描述符
 * @param[in]	cmd 发送命令
 * @param[in]	tbuf 发送内容
 * @param[in]	tlen 发送长度（不超过4000byte）
 * @param[in]	rbuf 读取内容
 * @param[in]	rlen 读取长度（不超过4000byte）
 * @param[in]   wait 发送tbuf内容后，等待多久读取rbuf，单位是us
 * @retval	null
 * @remark 调试版本中，在发送数据后固定延时5ms之后才读取数据，
    发布版可视情况删除

CS     _______                               _____________
.            |______________________________|
CLK    ________                           _____________________
.              |xxxxxxxxxxxxxxxxxxxxxxxxxx|
.               <-tbuf->
MOSI   _________         ________________________________
.               |xxxxxxx|
.                       |<--t1-->
MISO   _________                          ______________
.               |________________xxxxxxxx|
.                                <-rbuf->

1. tbuf开头是"GLINK"的ASCII
2. 某些命令需要在在读取过程需要延时，比如需要FPGA读取外部芯片寄存器，
FPGA接收tbuf后立即执行对外设操作，主控等待t1时间后，再发送时钟。
我当初一刀切，对所有通信用 _fpga_transfer 宏替换，强制t1=100us
*/
unsigned int __fpga_transfer(struct fpga_dev *dev, unsigned char cmd, char *tbuf, int tlen, char *rbuf, int rlen, int wait);

// 兼容以前的参数，默认发送命令后读取结果要等待100us，使用__fpga_transfer可自定义等待时间
// #define _fpga_transfer(dev, cmd, tbuf, tlen, rbuf, rlen) \
// 	__fpga_transfer(dev, cmd, tbuf, tlen, rbuf, rlen, 100)
static inline unsigned int _fpga_transfer(struct fpga_dev *dev,
                                          unsigned char    cmd,
                                          char            *tbuf,
                                          int              tlen,
                                          char            *rbuf,
                                          int              rlen)
{
    return __fpga_transfer(dev, cmd, tbuf, tlen, rbuf, rlen, 100);
}
#endif